package com.lzwork.gpt.utility.common;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.alibaba.fastjson.JSONObject;
import com.lzwork.utility.logger.LOGGER;
import com.lzwork.utility.logger.LOGGER.LogType;
import com.lzwork.utility.pair.Pair;
import com.lzwork.utility.str.StrUtility;

/**
 * @author LiZheng
 * @date 2023年11月8日 下午2:56:17
 */

public class Passage
{
	public final static char[] ENDERS =
	{ '。', '？', '?', '!', '！' };

	public final static String[] FULL_ENDERS =
	{ ". ", "!", "?", "\n", "\r", "。", "！", "？" };

	public final static Set<Character> ENDER_SET;

	static
	{
		ENDER_SET = new HashSet<>();
		for (char c : ENDERS)
		{
			ENDER_SET.add(c);
		}
	}

	public static String mergeLines(String input)
	{
		String temp = input.replace("\r", "\n");

		String[] parts = temp.split("\n");

		StringBuilder sb = new StringBuilder();

		for (String str : parts)
		{
			if (str.trim().isEmpty())
				continue;

			sb.append(str);
			char c = str.charAt(str.length() - 1);
			if (!ENDER_SET.contains(c))
				sb.append("。");
		}

		return sb.toString();
	}

	public static String cutPassage(String input, int maxLen, boolean cutEnder)
	{
		if (maxLen <= 0)
		{
			LOGGER.log(LOGGER.PARSE, "Invalid length limit: " + maxLen + ". Set to default value:2000");
			maxLen = 2000;
		}

		if (input.length() <= maxLen)
			return input;

		String target = input.substring(0, maxLen);

		if (cutEnder)
		{
			int best = -1;
			for (String mark : FULL_ENDERS)
			{
				int pos = target.lastIndexOf(mark);

				if (pos >= 0)
				{
					pos = pos + mark.length();
					if (pos > best)
						best = pos;
				}
			}
			if (best > 0)
				target = target.substring(0, best);
		}

		return target;
	}

	public static List<String> cutSentences(String text)
	{
		return cutSentences(text, 0, 0);
	}

	public static List<String> cutSentences(String text, int minInnerLen)
	{
		return cutSentences(text, minInnerLen, 0);
	}

	public static List<String> cutSentences(String text, int minInnerLen, int minOutLen)
	{
		List<String> allParts = new ArrayList<>();
		String[] partsOut = text.split("[\\n]|[\\r]");

		for (int i = 0; i < partsOut.length; i++)
		{
			String po = partsOut[i].trim();
			if (!StrUtility.stringValid(po))
				continue;

			List<String> inParts = StrUtility.splitWithSuffix(po, ENDERS);

			if (minInnerLen > 0)
				inParts = StrUtility.mergeToLength(inParts, minInnerLen, "", false);
			allParts.addAll(inParts);
		}

		if (minOutLen <= 0)
			return allParts;

		return StrUtility.mergeToLength(allParts, minOutLen, "\n", false);
	}

	public static List<JSONObject> pickJsonObjects(String input, int numLimit, LogType doLog)
	{
		List<JSONObject> result = new ArrayList<>();

		List<String> parts = pickJsonRanges(input);

		for (String str : parts)
		{
			int index = 0;
			try
			{
				JSONObject obj = JSONObject.parseObject(str);
				result.add(obj);

			} catch (Exception e)
			{
				if (doLog != LogType.None)
				{
					String info = "Parse json object failed at [" + index + "]";
					if (doLog == LogType.Full)
						info += ". Content is: \n" + str;
					LOGGER.warn(LOGGER.PARSE, info);
				}
			} finally
			{
				index++;

				if (numLimit > 0 && result.size() >= numLimit)
					break;
			}
		}

		return result;
	}

	public static List<String> pickJsonRanges(String input)
	{
		return pickJsonRanges(input, -1);
	}

	public static List<String> pickJsonRanges(String input, int numLimit)
	{
		List<String> result = new ArrayList<>();

		int begin = input.indexOf('{');
		if (begin >= 0)
		{
			char[] cArray = input.toCharArray();
			int num = 1;
			for (int i = begin + 1; i < cArray.length; i++)
			{
				char c = cArray[i];

				if (c == '{')
					num++;
				else if (c == '}')
					num--;

				if (num == 0)
				{
					int end = i + 1;
					String cut = input.substring(begin, end);
					if (StrUtility.stringValid(cut))
						result.add(cut);

					if (numLimit > 0)
					{
						numLimit--;
						if (numLimit == 0)
							break;
					}

					String remain = input.substring(end);
					if (StrUtility.stringValid(remain))
						result.addAll(pickJsonRanges(remain, numLimit));

					break;
				}
			}
		}

		return result;
	}

	public static JSONObject toJObj(String jsonStr)
	{
		String str = jsonStr;
		int split;
		split = str.indexOf('{');
		if (split > 0)
			str = str.substring(split);
		split = str.lastIndexOf('}');
		if (split > 0 && split < str.length() - 1)
			str = str.substring(0, split + 1);

		try
		{
			JSONObject obj = JSONObject.parseObject(str);
			return obj;

		} catch (Exception e)
		{
			e.printStackTrace();
			return null;
		}
	}

	public static class CutResult implements Iterable<String>
	{
		List<String> lines = new ArrayList<>();
		List<String> logs = new ArrayList<>();

		public int size()
		{
			return lines.size();
		}

		public List<String> logs()
		{
			return logs;
		}

		public void add(String line)
		{
			lines.add(line);
		}

		public void addAll(Collection<? extends String> line)
		{
			lines.addAll(line);
		}

		public void appendLog(String log)
		{
			logs.add(log);
		}

		@Override
		public Iterator<String> iterator()
		{
			return lines.iterator();
		}
	}

	public static CutResult cutRawContent(String input, String desc, int maxLen)
	{
		CutResult result = new CutResult();

		if (maxLen <= 0)
		{
			result.add(input);
			return result;
		}

		String[] lines = input.split("\n");

		List<String> buffer = new ArrayList<>();
		int nowLen = 0;

		int index = 0;

		for (String str : lines)
		{
			String line = str;
			index++;
			if (line.isEmpty())
				continue;

			if (line.length() > maxLen)
			{
				if (buffer.size() > 0)
				{
					result.add(StrUtility.combineString(buffer, "\n"));
					nowLen = 0;
					buffer.clear();
				}

				Pair<String, List<String>> x = cutByEnder(line, maxLen);
				result.addAll(x.second());

				String cutLog = "Cut " + x.second().size() + " parts from single line for " + line.length() + " > " + maxLen
						+ " in [" + index + "] " + desc;
				result.appendLog(cutLog);

				line = x.first();
			}

			if (nowLen > 0)
			{
				int nextLen = nowLen + line.length();

				if (nextLen > maxLen)
				{
					result.add(StrUtility.combineString(buffer, "\n"));
					nowLen = 0;
					buffer.clear();
				}
			}

			buffer.add(line);
			nowLen += line.length();
		}

		if (nowLen > 0)
		{
			result.add(StrUtility.combineString(buffer, "\n"));
		}

		return result;
	}

	static Pair<String, List<String>> cutByEnder(String input, int maxLen)
	{
		String raw = input;
		List<String> parts = new ArrayList<>();

		while (raw.length() > maxLen)
		{
			int index = raw.lastIndexOf('。', maxLen);
			if (index < 0)
				index = raw.indexOf("。", maxLen);

			if (index < 0)
				break;

			String part = raw.substring(0, index + 1);
			parts.add(part);
			raw = raw.substring(index + 1);
		}

		parts.add(raw);

		return new Pair<>(input, parts);
	}

	public static void main(String[] args)
	{
		String input = "aa\nbbbbb!!c。dd\rnnnn";

		System.out.println(cutSentences(input, 3, 0));

		input = "啊啊啊啊啊。啊啊啊啊啊啊.啊啊啊啊啊啊啊啊";
		String cut;
		System.out.println(input);
		System.out.println("-------------");
		cut = cutPassage(input, 10, false);
		System.out.println(cut);
		System.out.println("-------------");
		cut = cutPassage(input, 10, true);
		System.out.println(cut);
		System.out.println("-------------");
	}
}
